Skip to content

Comments

Implement agent identity profile v01 (Signature-Agent + x509 delegation)#50

Merged
hammadtq merged 49 commits intomainfrom
pr-6-agent-identity
Feb 24, 2026
Merged

Implement agent identity profile v01 (Signature-Agent + x509 delegation)#50
hammadtq merged 49 commits intomainfrom
pr-6-agent-identity

Conversation

@hammadtq
Copy link
Contributor

Summary

This PR implements the PR #6 spec file (docs/specs/draft-openbotauth-agent-identity-00.md) in code, aligned to the current spec text (no ADT changes, no 402 semantics changes).

Verifier (packages/verifier-service)

  • Parse Signature-Agent as RFC 8941 Structured Field Dictionary with signature-label selection.
  • Keep backward compatibility with legacy plain URL Signature-Agent.
  • Retain and use signature label from Signature-Input in verification flow.
  • Add optional feature-flagged x5c/x5u validation:
    • leaf cert public key must match JWK
    • chain validation to configured trust anchors
    • SSRF/redirect protections on x5u fetch
  • Tighten /.well-known/http-message-signatures-directory URL handling.

Registry (packages/registry-service)

  • Add optional agent identity fields (oba_agent_id, oba_parent_agent_id, oba_principal) and migration.
  • Add Signature Agent Card endpoint: /.well-known/signature-agent-card.
  • Add cert issuance MVP endpoints:
    • POST /v1/certs/issue
    • POST /v1/certs/revoke
    • GET /.well-known/ca.pem
  • Add local CA issuance utilities and persist issued cert metadata.
  • Attach x5c to JWKS for active, scoped agent certs.

Bot CLI (packages/bot-cli)

  • Add option to emit Signature-Agent in dictionary format (legacy remains default).

Portal (apps/registry-portal)

  • Minimal support for oba_* fields in create/detail views.

Docs

  • Updated verifier/registry/docs snippets for dictionary Signature-Agent, signature-agent-card, and x509 config/limitations.

Migration

  • infra/neon/migrations/007_agent_identity_and_certs.sql

Notes

  • CA in this MVP is local/self-hosted and trust-anchor based (not WebPKI).
  • x5u currently fetches leaf cert only; AIA chain building is not implemented.

Test Coverage

  • Added/updated tests for parser label handling, structured dictionary parsing, x509 validation, and CA SAN issuance behavior.
  • Ran targeted verifier parser tests successfully:
    • pnpm --filter @openbotauth/verifier-service test --run signature-parser

hammadtq and others added 30 commits February 22, 2026 22:19
Replace insecure String.includes() check with proper URL hostname
validation to prevent authorization bypass via crafted URLs like
evil-trusted.com.attacker.com or attacker.com/trusted.com/fake.json.

The new isTrustedDirectory() method:
- Parses URLs to extract and compare hostnames
- Validates exact match or proper subdomain boundary
- Case-insensitive comparison
- Handles trusted directories with or without scheme prefix
- Fix is_active to check not_before <= now() in addition to not_after
- Add /v1/certs/public-status endpoint for relying party revocation checks
- Fix x5c attachment to only serve valid certificates (not expired/not-yet-valid)
- Require status='active' for agent_id lookup in signature-agent-card
- Change CLI default Signature-Agent format from legacy to dict
- Add .nvmrc file (Node 20)
- Update README with not_before field and public-status endpoint docs
- Require PoP signature for cert issuance (prevents issuing certs for
  keys you do not control)
- Validate fingerprint_sha256 format (64 hex chars) on public-status endpoint
- Add fingerprint computation guidance to README for mTLS integrators
- Add type checks and signature length validation (64 bytes for Ed25519)
- Disallow future timestamps (30s drift tolerance, 5min max age)
- Bind proof to agent_id: cert-issue:{agent_id}:{timestamp}
- Use object form for webcrypto.subtle.verify
- Fix fingerprint error message (accepts uppercase, normalizes to lowercase)
- Update README with native crypto fingerprint example
- Remove Issue Certificate button from portal (add CLI instructions)
- Add oba-bot cert issue command with PoP support
- Remove kid-only cert issuance (require agent_id for PoP binding)
- Add --private-key-path to CLI for portal-created agents
- Update portal snippet with full command (token + private-key-path)
- Clarify README: 30s future drift tolerated for clock skew
- Add happy-path PoP test with real Ed25519 crypto verification
- Auto-detect key format: JWK JSON (portal agent creation) or PEM (Setup page)
- Extract PEM from .txt bundle files (Setup.tsx downloads keys in .txt)
- Update portal snippet to show correct .json extension
- Update README to document both supported formats
- Portal: use full agent ID in private key filename example
  (was truncated with slice(0,8) which didnt match actual filename)
- CLI: validate jwk.x field exists (not just d)
- CLI: import minimal JWK object (kty, crv, x, d only)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Test valid=false for revoked certs (includes revoked_at, revoked_reason)
- Test valid=false for expired certs (not_after in the past)
- Test 404 when cert not found by fingerprint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add migration 009 with pop_nonces table and check_pop_nonce function
- Check nonce before issuing certificate (rejects replayed proofs)
- Graceful degradation if migration not applied
- Add test for replay detection
- Document replay protection in README

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove dead issueCert() from portal API (lacks PoP proof param)
- Add oba_* field validation in agents-api.ts (type check, length limit)
- Normalize fingerprint in /v1/certs/status (lowercase, 64 hex chars)
- Fix timestamp drift comment to match code (+30s tolerance)
- Update Node engine to >=20.0.0 in proxy and verifier-client
- Add E2E signature verification tests (5 tests)
- Fix portal UI cert status logic to check not_before (add "pending" state)
hammadtq and others added 19 commits February 23, 2026 17:57
- Add tag="web-bot-auth" to Signature-Input (MUST per IETF draft)
- Add signature-agent;key="label" covered component format for
  dictionary member selection (RFC 8941)
- Increase nonce from 16 to 64 bytes (RECOMMENDED per IETF draft)
- Fix keyid to use full JWK thumbprint without truncation
- Add relabeling support in verifier: parse ;key= parameter from
  covered components to select correct dictionary member

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update test assertions to expect the new IETF-compliant format:
- signature-agent;key="sig1" covered component format
- tag="web-bot-auth" in Signature-Input

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update parse_covered_headers in all clients to handle the IETF draft
signature-agent;key="label" format. When parsing covered components,
extract only the base header name (before ;) for lookup purposes.

Files updated:
- packages/verifier-client/src/headers.ts
- plugins/wordpress-openbotauth/includes/Verifier.php
- sdks/python/src/openbotauth_verifier/headers.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Enforce leaf certificate EKU includes clientAuth (1.3.6.1.5.5.7.3.2)
  when EKU extension is present (default: enabled)
- Add optional SAN URI binding validation for soft identity pinning
- Add comprehensive tests for EKU and SAN validation scenarios
- Note: Node.js exposes EKU OIDs via `keyUsage` property (not `extKeyUsage`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update parseCoveredHeaders regex to handle RFC 9421 component parameters
  like "signature-agent";key="sig1"
- Add tests for new IETF format with ;key= parameters
- Bump version to 0.1.7 (requires npm republish)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hammadtq
Copy link
Contributor Author

LGTM.

@hammadtq hammadtq merged commit 77a0749 into main Feb 24, 2026
1 check passed
@hammadtq hammadtq deleted the pr-6-agent-identity branch February 24, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant